package cn.iocoder.yudao.module.forward.mqtt.dataSource;

import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.forward.controller.admin.eew.vo.EewSaveReqVO;
import cn.iocoder.yudao.module.forward.controller.admin.eqr.vo.EqrSaveReqVO;
import cn.iocoder.yudao.module.forward.dal.dataobject.scope.ScopeInfo;
import cn.iocoder.yudao.module.forward.dal.dataobject.strategy.StrategyDO;
import cn.iocoder.yudao.module.forward.mqtt.MqttConnect;
import cn.iocoder.yudao.module.forward.mqtt.MqttManager;
import cn.iocoder.yudao.module.forward.mqtt.MessageHandler;
import cn.iocoder.yudao.module.forward.mqtt.message.EewMessage;
import cn.iocoder.yudao.module.forward.mqtt.MqttConstants;
import cn.iocoder.yudao.module.forward.mqtt.MqttInfo;
import cn.iocoder.yudao.module.forward.service.eew.EewService;
import cn.iocoder.yudao.module.forward.service.eqr.EqrService;
import cn.iocoder.yudao.module.forward.service.scope.ScopeService;
import cn.iocoder.yudao.module.forward.service.strategy.StrategyService;
import com.alibaba.druid.util.StringUtils;
import com.alibaba.fastjson.JSONObject;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;

@Slf4j
@Component
public class SourceMessageHandler implements MessageHandler {
    @Resource(name = "BrokerMqttManager")
    private MqttManager mqttManager;
    @Resource
    private ScopeService mScopeService;
    @Resource
    private StrategyService mStrategyService;
    @Resource
    private EewService mEewService;
    @Resource
    private EqrService mEqrService;

    @Override
    public void handleMessage(MqttInfo mqttInfo, String topic, String data) throws Exception {
        String topicType = (String) mqttInfo.getTopics().get(topic);
        if (topicType == null) {
            log.error("{}({})不存在该主题:{}", mqttManager.getTag(), mqttInfo.getName(), topic);
            return;
        }

        EewResult eewResult = new EewResult();
        eewResult.setType(topicType);
        eewResult.setOrgTopic(topic);
        eewResult.setOrgMsg(data);
        eewResult.setSourceId(mqttInfo.getId());
        eewResult.setStatus(false);

        try {
            EewMessage msg = getMsg(mqttInfo, data, topicType);
            if (msg == null) {
                throw new RuntimeException("消息解析失败");
            }
            if (topicType.equals(MqttConstants.TOPIC_TYPE_EQR) && msg.getOriTime() == null) {
                if (isSign()) {
                    log.info("旧版本速报协议, 不进行验签");
                } else {
                    log.info("旧版本速报协议");
                }
                EewMessage newMsg = new EewMessage();
                newMsg.setMsgId(msg.getMsgId());
                newMsg.setMsgType(msg.getMsgType());
                newMsg.setEewId(msg.getSendTime());
                newMsg.setLocName(msg.getMsgSource());
                newMsg.setEpiLat(msg.getCheckCode());
                newMsg.setEpiLon(msg.getVersion());
                newMsg.setFocDepth(msg.getEewId());
                newMsg.setMagnitude(msg.getSerialNumber());
                newMsg.setOriTime(msg.getProducer());
                msg = newMsg;
            } else if (isSign()) {
                if (!verifyMessage(data)) {
                    throw new RuntimeException("验签失败");
                }
                log.error("{}({}), 验签成功", mqttManager.getTag(), mqttInfo.getName());
            }
            eewResult.setMsg(msg);
            // TODO: 2025/4/30
            //根据 mSourceMqttInfo.getSourceId()查询授权topic
            checkScope(mqttInfo, topicType, eewResult);
        } catch (Exception e) {
            eewResult.setStatus(false);
            eewResult.setResult("消息处理发生异常: " + e.getMessage());
            log.error(eewResult.getResult());
            saveEewResult(eewResult);
        }
    }

    /**
     * 检查授权
     *
     * @param mqttInfo
     * @param topicType
     * @param eewResult
     */
    private void checkScope(MqttInfo mqttInfo, String topicType, EewResult eewResult) {
        String data = eewResult.getOrgMsg();
        List<ScopeInfo> scopeInfos = mScopeService.selectBySourceId(mqttInfo.getId(), topicType);
        for (ScopeInfo scopeInfo : scopeInfos) {
            try {
                String name = mqttManager.getMqttNameById(scopeInfo.getBrokerId());
                MqttConnect mqttConnect = mqttManager.getMqttConnect(name);
                if (mqttConnect == null) {
                    throw new RuntimeException("转发服务(" + name + ")不存在");
                }
                eewResult.setBrokerId(mqttConnect.getMqttInfo().getId());
                checkStrategy(scopeInfo.getId(), eewResult.getMsg());
                log.info("策略通过");
                //如果存在topic 则查询策略   有策略时如果通过则转发，  无策略是根据默认开关及默认配置决定是否转发
                //根据授权关联的broker发送数据
                data = beforePublish(data);
                eewResult.setTime(LocalDateTime.now());
                eewResult.setForwardTopic(scopeInfo.getTopic());
                String forwardMsg = mqttConnect.publish(scopeInfo.getTopic(), data, MqttConstants.MQTT_QOS);
                eewResult.setForwardMsg(forwardMsg);
                eewResult.setResult("转发成功");
                eewResult.setStatus(true);
                saveEewResult(eewResult);
            } catch (Exception e) {
                eewResult.setResult(e.getMessage());
                log.error(eewResult.getResult());
                saveEewResult(eewResult);
            }
        }
    }

    /**
     * 解析消息
     *
     * @param mqttInfo
     * @param data
     * @param topicType
     * @return
     */
    private EewMessage getMsg(MqttInfo mqttInfo, String data, String topicType) {
        EewMessage eewMessage = null;
        try {
            switch (topicType) {
                case MqttConstants.TOPIC_TYPE_EEW:
                    eewMessage = JSONObject.parseObject(data, EewMessage.class);
                    log.info("信息源({})收到预警消息:{}", mqttInfo.getName(), eewMessage);
                    break;
                case MqttConstants.TOPIC_TYPE_EQR:
                    eewMessage = JSONObject.parseObject(data, EewMessage.class);
                    log.info("信息源({})收到速报消息:{}", mqttInfo.getName(), eewMessage);
                    break;
                default:
                    log.info("信息源({})收到异常消息:{}", mqttInfo.getName(), data);
                    break;
            }
        } catch (Exception e) {

        }
        return eewMessage;
    }

    /**
     * 发送前处理  可以处理防篡改
     *
     * @param data
     * @return
     */
    private String beforePublish(String data) {
        return data;
    }

//    /**
//     * 收到消息后  可以处理防篡改
//     *
//     * @param data
//     * @return
//     */
//    private String onMessage(String data) {
//        return data;
//    }

    /**
     * 策略校验
     *
     * @return
     */
    private boolean checkStrategy(Integer scopeId, EewMessage eewMessage) throws Exception {
        StrategyDO strategy = mStrategyService.getStrategyByScopeId(scopeId);
        if (strategy == null) {
            //执行默认策略
            log.info("未发现策略，执行默认策略");
            return defaultStrategy();
        }

        //策略包含震级，并且震级大于预警中的震级，则拦截取消转发
        if (strategy.getMagnitude() != null) {
            float mag = Float.parseFloat(eewMessage.getMagnitude());
            if (mag < strategy.getMagnitude()) {
                throw new RuntimeException("策略未通过, 震级(" + eewMessage.getMagnitude() + ")未超过阈值(" + strategy.getMagnitude() + ")");
            }
        }
        //策略包含烈度，并且烈度大于预警中的震中烈度，则拦截取消转发
        if (strategy.getIntensity() != null && eewMessage.getEpiIntensity() != null) {
            float intensity = Float.parseFloat(eewMessage.getEpiIntensity());
            if (intensity < strategy.getIntensity()) {
                throw new RuntimeException("策略未通过, 震中烈度(" + intensity + ")未超过阈值(" + strategy.getIntensity() + ")");
            }
        }
        String str = null;
        //策略包含地区限制，并且预警震中位置不包含该地区名称，则拦截取消转发
        if (!StringUtils.isEmpty(strategy.getArea())) {
            String[] split = strategy.getKeywords().split(",");
            for (String area : split) {
                if (eewMessage.getLocName().contains(area)) {
                    log.info("策略通过, 震中位置({})包含地区({})", eewMessage.getLocName(), area);
                    return true;
                }
            }
            str = "震中位置(" + eewMessage.getLocName() + ")不在地区范围(" + strategy.getArea() + ")内";
        }
        //策略包含地区限制，并且预警震中位置不包含该地区名称，则拦截取消转发
        if (!StringUtils.isEmpty(strategy.getKeywords())) {
            String[] split = strategy.getKeywords().split(",");
            for (String keyword : split) {
                if (eewMessage.getLocName().contains(keyword)) {
                    log.info("策略通过, 震中位置({})包含关键词({})", eewMessage.getLocName(), keyword);
                    return true;
                }
            }
            if (str != null) {
                str += ", ";
            }
            str += "震中位置(" + eewMessage.getLocName() + ")不包含关键词(" + strategy.getKeywords() + ")";
        }
        if (str != null) {
            throw new RuntimeException("策略未通过, " + str);
        }
        return true;
    }

    private boolean defaultStrategy() {
        // TODO: 2025/5/5 记录日志
        return true;
    }

    /**
     * 是否验签
     *
     * @return
     */
    private boolean isSign() {
        return false;
    }

    private void saveEewResult(EewResult eewResult) {
        switch (eewResult.getType()) {
            case MqttConstants.TOPIC_TYPE_EEW:
                addEew(eewResult);
                break;
            case MqttConstants.TOPIC_TYPE_EQR:
                addEqr(eewResult);
                break;
        }
    }

    private void addEew(EewResult eewResult) {
        EewSaveReqVO eewSaveReqVO = BeanUtils.toBean(eewResult.getMsg(), EewSaveReqVO.class);
        eewSaveReqVO.setForwardStatus(eewResult.getStatus());
        eewSaveReqVO.setForwardResult(eewResult.getResult());
        eewSaveReqVO.setOriginalTopic(eewResult.getOrgTopic());
        eewSaveReqVO.setOriginalMsg(eewResult.getOrgMsg());
        eewSaveReqVO.setForwardTopic(eewResult.getForwardTopic());
        eewSaveReqVO.setForwardMsg(eewResult.getForwardMsg());
        eewSaveReqVO.setForwardTime(eewResult.getTime());
        eewSaveReqVO.setSourceId(eewResult.getSourceId());
        eewSaveReqVO.setBrokerId(eewResult.getBrokerId());
        mEewService.createEew(eewSaveReqVO);
    }

    private void addEqr(EewResult eewResult) {
        EqrSaveReqVO eqrSaveReqVO = BeanUtils.toBean(eewResult.getMsg(), EqrSaveReqVO.class);
        eqrSaveReqVO.setForwardStatus(eewResult.getStatus());
        eqrSaveReqVO.setForwardResult(eewResult.getResult());
        eqrSaveReqVO.setOriginalTopic(eewResult.getOrgTopic());
        eqrSaveReqVO.setOriginalMsg(eewResult.getOrgMsg());
        eqrSaveReqVO.setForwardTopic(eewResult.getForwardTopic());
        eqrSaveReqVO.setForwardMsg(eewResult.getForwardMsg());
        eqrSaveReqVO.setForwardTime(eewResult.getTime());
        eqrSaveReqVO.setSourceId(eewResult.getSourceId());
        eqrSaveReqVO.setBrokerId(eewResult.getBrokerId());
        mEqrService.createEqr(eqrSaveReqVO);
    }

    @Data
    class EewResult {
        private String orgTopic;
        private String orgMsg;
        private String forwardTopic;
        private String forwardMsg;
        private EewMessage msg;
        private Boolean status;
        private String result;
        private String type;
        private LocalDateTime time;
        private Integer sourceId;
        private Integer brokerId;
    }
}
